#include "FLOAT.h"

FLOAT F_mul_F(FLOAT a, FLOAT b) {
	return (FLOAT)(((long long)a * (long long)b) >> 16);
}

FLOAT F_div_F(FLOAT a, FLOAT b) {
	/* Dividing two 64-bit integers needs the support of another library
	 * `libgcc', other than newlib. It is a dirty work to port `libgcc'
	 * to NEMU. In fact, it is unnecessary to perform a "64/64" division
	 * here. A "64/32" division is enough.
	 *
	 * To perform a "64/32" division, you can use the x86 instruction
	 * `div' or `idiv' by inline assembly. We provide a template for you
	 * to prevent you from uncessary details.
	 *
	 *     asm volatile ("??? %2" : "=a"(???), "=d"(???) : "r"(???), "a"(???), "d"(???));
	 *
	 * If you want to use the template above, you should fill the "???"
	 * correctly. For more information, please read the i386 manual for
	 * division instructions, and search the Internet about "inline assembly".
	 * It is OK not to use the template above, but you should figure
	 * out another way to perform the division.
	 */

	//初始化符号位为正，用于处理结果的正负
	int sign = 1;
	//若分子或分母为负，改变符号位并取绝对值
	if (a < 0)
		sign = -sign, a = -a;
	if (b < 0)
		sign = -sign, b = -b;
	//初始化整数结果，通过64/32位除法计算
	int res = a / b;
	//余数用于后续精确计算
	a = a % b;
	//循环16次，每次将余数左移一位，以计算小数部分
	int i;
	for (i = 0; i < 16; i++)
	{
		a <<= 1;
		res <<= 1;
		//若左移后的余数大于等于除数，从余数中减去除数，并将结果加一
		if (a >= b)
		{
			a = a - b;
			res++;
		}
	}
	//返回最终结果，乘以符号位以恢复原始符号
	return res * sign;
}

FLOAT f2F(float a) {

	/* You should figure out how to convert `a' into FLOAT without
	 * introducing x87 floating point instructions. Else you can
	 * not run this code in NEMU before implementing x87 floating
	 * point instructions, which is contrary to our expectation.
	 *
	 * Hint: The bit representation of `a' is already on the
	 * stack. How do you retrieve it to another variable without
	 * performing arithmetic operations on it directly?
	 */

	int b = *(int *)&a;//将浮点数a强制类型转换为int，以操作其内部的二进制表示
	int sign = b >> 31;//提取浮点数的符号位：最高位为1表示负数，0表示正数
	int exp = (b >> 23) & 0xff; // 提取浮点数的指数部分：8位的指数字段，需要减去127得到真实指数值
	int x = b & 0x7fffff; // 提取浮点数的小数部分：23位的小数字段
	//如果指数不为0（非规格化数），则将小数点移至第一位
	if (exp != 0)
		x += 1 << 23;
	//// 将指数调整到NEMU的FLOAT类型范围（-126到127），这里先统一减去150
	exp -= 150;
	 // 如果指数小于-16，右移小数部分以规范化数值
	if (exp < -16)
		x >>= -16 - exp;
	/// 如果指数大于-16，左移小数部分以规范化数值
	else if (exp > -16)
		x <<= 16 + exp;
	if (exp > -16)
		x <<= 16 + exp;
	// 根据符号位返回最终的float类型值
	return sign == 0 ? x : -x;
}

FLOAT Fabs(FLOAT a) {
	return a < 0 ? -a : a;
}

/* Functions below are already implemented */
FLOAT sqrt(FLOAT x) {
	FLOAT dt, t = int2F(2);

	do {
		dt = F_div_int((F_div_F(x, t) - t), 2);
		t += dt;
	} while(Fabs(dt) > f2F(1e-4));

	return t;
}

FLOAT pow(FLOAT x, FLOAT y) {
	/* we only compute x^0.333 */
	FLOAT t2, dt, t = int2F(2);

	do {
		t2 = F_mul_F(t, t);
		dt = (F_div_F(x, t2) - t) / 3;
		t += dt;
	} while(Fabs(dt) > f2F(1e-4));

	return t;
}

